#include "map_manager.h"
#include "tool.h"

using namespace alice;

MapManager* MapManager::instance_ = nullptr;

bool MapManager::Load() {
  return Parse("level-1", Tool::CurrentPath() + "/res/maps/test.tmx");
}

bool MapManager::Parse(std::string id, std::string source) {
  TiXmlDocument xml;
  xml.LoadFile(source);
  if (xml.Error()) {
    SDL_Log("Failed to load: %s", source.c_str());
    return false;
  }

  TiXmlElement* root = xml.RootElement();
  int row, columns, tile_size = 0;
  root->Attribute("width", &columns);
  root->Attribute("height", &row);
  root->Attribute("tilewidth", &tile_size);

  TileSetList tile_sets;
  for (TiXmlElement* e = root->FirstChildElement(); e != nullptr; e = e->NextSiblingElement()) {
    if (e->Value() == std::string("tileset")) {
      tile_sets.push_back(ParseTileSet(e));
    }
  }

  GameMap* game_map = new GameMap();
  for (TiXmlElement* e = root->FirstChildElement(); e != nullptr; e = e->NextSiblingElement()) {
    if (e->Value() == std::string("layer")) {
      game_map->AddLayer(ParseTileLayer(e, tile_sets, tile_size, row, columns));
    }
  }

  maps_[id] = game_map;
  return true;
}

TileSet MapManager::ParseTileSet(TiXmlElement* xml_tile_set) {
  TileSet tile_set;

  tile_set.name = xml_tile_set->Attribute("name");
  xml_tile_set->Attribute("firstgid", &tile_set.first_id);
  xml_tile_set->Attribute("tilecount", &tile_set.tile_count);
  tile_set.last_id = (tile_set.first_id + tile_set.tile_count) - 1;
  xml_tile_set->Attribute("columns", &tile_set.columns);
  tile_set.row = tile_set.tile_count / tile_set.columns;
  xml_tile_set->Attribute("tilewidth", &tile_set.tile_size);

  TiXmlElement* image = xml_tile_set->FirstChildElement();
  tile_set.source = image->Attribute("source");

  return tile_set;
}

TileLayer* MapManager::ParseTileLayer(TiXmlElement* xml_layer, TileSetList tile_sets, int tile_size, int row, int columns) {
  TiXmlElement* data = nullptr;
  for (TiXmlElement* e = xml_layer->FirstChildElement(); e != nullptr; e = e->NextSiblingElement()) {
    if (e->Value() == std::string("data")) {
      data = e;
      break;
    }
  }

  std::string matrix(data->GetText());
  std::istringstream iss(matrix);
  std::string id;
  
  TileMap tile_map(row, std::vector<int>(columns, 0));
  for (int i = 0; i < row; i++) {
    for (int j = 0; j < columns; j++) {
      std::getline(iss, id, ',');
      std::stringstream convertor(id);
      convertor >> tile_map[i][j];

      if (!iss.good()) {
        break;
      }
    }
  }
  
  return new TileLayer(tile_size, row, columns, tile_map, tile_sets);
}

void MapManager::Clean() {
  std::map<std::string, GameMap*>::iterator it;
  for (it = maps_.begin(); it != maps_.end(); it++) {
    it->second->Clear();
    SDL_Log("Map %s's layers is cleaned\n", it->first.c_str());
    delete it->second;
    SDL_Log("Map %s is cleaned\n", it->first.c_str());
  }
  maps_.clear();
}
